#include "hcsr04.h"

// 测量的模式(默认为测量液面到传感器的距离)
static uint8_t measure_mode = DISTANCE_MODE;
// 水位的总高程(mm)
static uint16_t height = 0;
// 存放测量时间
static u32 gMsHcCount = 0;

// 超声波初始化
void hsr04_init(void)
{
	// 定时器结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	// GPIO结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	// NVIC结构体
	NVIC_InitTypeDef NVIC_InitStructure;
	// GPIO时钟使能
	RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);

	// GPIOB6-TRIG
	GPIO_InitStructure.GPIO_Pin = HCSR04_TRIG;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	// 推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
	// 默认为低电平
	GPIO_ResetBits(HCSR04_PORT, HCSR04_TRIG);

	// GPIOB5-ECHO
	GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO;
	// 模拟输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
	GPIO_ResetBits(HCSR04_PORT, HCSR04_ECHO);

	// 定时器时钟使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	// 定时器初始化
	TIM_DeInit(TIM2);
	// 预装载值（计数1000次）
	TIM_TimeBaseStructure.TIM_Period = (1000 - 1);
	// 分频系数（1us一次）
	TIM_TimeBaseStructure.TIM_Prescaler = (72 - 1);
	// 不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	// TIM向上计数模式
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	// 根据TIM结构体初始化定时器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	// 清除一次更新中断（避免刚初始化时就触发中断）
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	// 定时器中断使能
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

	// NVIC初始化
	// 设置NVIC中断组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	// 设置定时器2中断
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	// 设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	// 设置中断子优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	// 中断使能
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 中断初始化
	NVIC_Init(&NVIC_InitStructure);

	// 默认关闭定时器
	TIM_Cmd(TIM2, DISABLE);
}

/*
 *==============================================================================
 *函数名称:TIM2_IRQHandler
 *函数功能:定时器2中断服务函数
 *函数参数:无
 *返回值:无
 *备	注:无
 *==============================================================================
 */
void TIM2_IRQHandler(void)
{
	// 检查TIM2是否发生中断
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
		// 清除中断更新标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		gMsHcCount++;
	}
}

/*
 *==============================================================================
 *函数名称:Hcsr04_OpenTimerForHc
 *函数功能:开启定时器
 *函数参数:无
 *返回值:无
 *备	注:无
 *==============================================================================
 */
static void Hcsr04_OpenTimerForHc(void)
{
	// 清除定时器2的计数
	TIM_SetCounter(TIM2, 0);
	// 毫秒数
	gMsHcCount = 0;
	// 定时器使能
	TIM_Cmd(TIM2, ENABLE);
}

/*
 *==============================================================================
 *函数名称:Hcsr04_CloseTimerForHc
 *函数功能:关闭定时器
 *函数参数:无
 *返回值:无
 *备	注:无
 *==============================================================================
 */
static void Hcsr04_CloseTimerForHc(void)
{
	// 使能定时器
	TIM_Cmd(TIM2, DISABLE);
}

/*
 *==============================================================================
 *函数名称:Hcsr04_GetEchoTimer
 *函数功能:获取定时器定时时间
 *函数参数:无
 *返回值:无
 *备	注:无
 *==============================================================================
 */
static u32 Hcsr04_GetEchoTimer(void)
{
	u32 t = 0;
	// 得到毫秒
	t = gMsHcCount * 1000;
	// 得到微秒
	t += TIM_GetCounter(TIM2);
	// 将TIM2的计数寄存器清零
	TIM2->CNT = 0;
	// 延时50ms
	delay_ms(50);
	// 得到最终的时间
	return t;
}

/*
 *==============================================================================
 *函数名称:Med_Hcsr04_GetLength
 *函数功能:获取测量距离
 *函数参数:无
 *返回值:无
 *备	注:一次获取超声波测距数据，两次测量之间需要间隔一段时间，隔断回响信号
				 为了消除余震的影响，取五次数据的平均值进行加权滤波
 *==============================================================================
 */
uint16_t Med_Hcsr04_GetLength(void)
{
	u32 t = 0;
	int i = 0;
	uint16_t length_temp = 0;
	// 接收次数
	uint8_t recv_times = 5;
	uint32_t sum = 0;
	for (i = 0; i < recv_times; i++)
	{
		// TRIG口发送高电平
		TRIG_Send = 1;
		// 延时20微秒
		delay_us(20);
		// TRIG口发送低电平
		TRIG_Send = 0;
		// 等待接收口接收到高电平
		while (ECHO_Recv == 0)
			;
		// 打开定时器
		Hcsr04_OpenTimerForHc();
		// 等待接收口接收到低电平
		while (ECHO_Recv == 1)
			;
		// 关闭定时器
		Hcsr04_CloseTimerForHc();
		// 获取定时时间（单位为us）
		t = Hcsr04_GetEchoTimer();
		// 以毫米为单位
		length_temp = ((float)t / 58.0) * 10;
		// 取数据总和
		sum = length_temp + sum;
	}
	// 根据测量模式返回数据的平均值
	if (measure_mode == DEPTH_MODE)
		length_temp = height - (sum / recv_times);
	else if (measure_mode == DISTANCE_MODE)
		length_temp = sum / recv_times;
	return length_temp;
}
// 设置设备的测量模式
void set_measure_mode(int mode)
{
	measure_mode = mode;
	return;
}
// 设置设备水位的高程
void set_height(uint16_t val)
{
	height = val;
	return;
}
// 获取设备水位的高程
uint16_t get_height(void)
{
	return height;
}
